package com.fas.hehe.system.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;

import org.apache.commons.collections.CollectionUtils;

import com.fas.core.BaseService;
import com.fas.core.constant.R;
import com.fas.core.plugin.jfinal.kit.ModelKit;
import com.fas.core.plugin.tree.jstree.Node;
import com.fas.core.util.sequence.Sequence;
import com.fas.hehe.system.model.Organization;
import com.jfinal.aop.Before;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;

/**
 * 
 * @ClassName: OrganizationService
 * @Description: 组织机构业务处理类
 * @Copyright: Copyright (c) 2016 FAS
 * @anthor yixiaoping<thinker1013@163.com>
 * @since 2016年1月25日 下午11:21:54
 * @version V1.0
 */
public class OrganizationService extends BaseService {

	/**
	 * 根据组织机构ID，查询组织机构对象
	 * 
	 * @param orgId
	 *            组织机构编码
	 * @return
	 */
	public Organization findOrganizationById(Long orgId) {
		return Organization.dao.findById(orgId);
	}

	/**
	 * 根据组织机构ID，查询组织下直属子节点
	 * 
	 * @param orgId
	 *            组织机构编码
	 * @return
	 */
	public List<Organization> findSubOrganizationById(Long orgId) {
		String sql = "select * from sys_organization where parent_id = ? and available =? order by priority asc";
		return Organization.dao.find(sql, orgId, R.Dict.STATUS_AVAILABLE);
	}

	/**
	 * 修改组织机构显示顺序
	 * 
	 * @param parentId
	 *            需要修改机构的父机构组织ID
	 * @param type
	 *            up : 显示顺序上移一位 ,down:显示顺序下移一位
	 * @param priority
	 *            当前需要进行修改机构的显示当前顺序
	 * @return
	 */
	@Before(Tx.class)
	public boolean changeOrganizationPriority(Long parentId, String type, int priority) {
		int otherPriority = 0;
		if ("up".equals(type)) {
			otherPriority = priority - 1;
		} else {
			otherPriority = priority + 1;
		}
		String sql = "select * from sys_organization where parent_id = ? and priority = ?";
		Organization curOrg = Organization.dao.findFirst(sql, parentId, priority);
		Organization otherOrg = Organization.dao.findFirst(sql, parentId, otherPriority);
		if (curOrg != null) {
			curOrg.set("priority", otherPriority);
			curOrg.update();
		}
		if (otherOrg != null) {
			otherOrg.set("priority", priority);
			otherOrg.update();
		}
		return true;
	}

	/**
	 * 删除组织机构（逻辑删除）
	 * 
	 * @param orgId
	 *            组织机构ID
	 * @return
	 */
	@Before(Tx.class)
	public boolean deleteOrganization(Long orgId) {
		Organization oldOrg = Organization.dao.findById(orgId);
		Organization newOrg = new Organization();
		ModelKit.clone(oldOrg, newOrg);

		oldOrg.set("available", R.Dict.STATUS_UNAVAILABLE);
		oldOrg.update();
		this.saveOperateLog(R.OperType.UPDATE, newOrg, oldOrg, this.getLoginUser());

		autoResetPriority(oldOrg.getParentId());
		return true;
	}

	/**
	 * 
	 * @Title:autoResetPriority
	 * @Description: <pre>
	 * 				重新设置机构所有子机构的优先级别 ,通常在删除机构后操作。
	 * 				 1）将子机构中，状态为“0-不可用”的记录优先级别全部更新为-1 
	 * 				 2) 将子机构中，状态为“1-可用”的记录，优先级别重新设置，但不改变原先这些值的前后顺序，只是让Priority值从1开始逐1递增
	 *              
	 * 				例如：   ID   状态     优先级                                   重置后状态为： ID   状态     优先级     
	 *             		101    1    1                     101    1    1
	 *                  102    1    2					  102    1    2
	 *                  103    0    3					  104    1    3
	 *                  104    1    4				      106    1    4
	 *                  105    0    5					  103    0    -1
	 *                  106    1    6					  105    0    -1
	 * </pre>
	 * @param parent_id
	 *            参数说明 父节点ID
	 * @return void 返回类型
	 * @throws
	 * @anthor yixiaoping<thinker163@163.com>
	 * @date 2016年1月28日 下午10:36:39
	 */
	public void autoResetPriority(Long parent_id) {
		// 将状态为"不可用"的记录，优先级全部设置为-1
		String updateSql = "update sys_organization set priority = ? where parent_id = ? and available =?";
		Db.update(updateSql, R.Const.DEFAULT_PRIORITY_VAL, parent_id, R.Dict.STATUS_UNAVAILABLE);

		// 重新设置状态为"可用"记录的优先级别值，但先后顺序不变
		String selectSql = "select * from sys_organization where parent_id =? and available =?";
		List<Organization> list = Organization.dao.find(selectSql, parent_id, R.Dict.STATUS_AVAILABLE);
		ArrayList<Organization> newList = new ArrayList<Organization>();
		for (int i = 0; i < list.size(); i++) {
			Organization org = list.get(i);
			org.setPriority(i + 1);
			newList.add(org);
		}
		list = null;
		Db.batchUpdate(newList, R.Const.DB_BATCH_SIZE);
	}

	/**
	 * 组织机构删除检查 1、判断是否有状态为“可用”的子机构 2、判断是否有状态为“可用”角色关联当前组织机构
	 * 3、判断是否有状态为“可用”用户关联当前组织机构
	 * 
	 * @param orgId
	 *            组织机构ID
	 * @return BOOLEAN {true: 允许删除, false:不允许删除}
	 */
	public boolean deleteOrganizationCheck(Long orgId) {
		boolean allowDelete = true;
		Long relationNum = 0l;
		String sqlOrg = "select count(1) as num from sys_organization where parent_id = ? and available = ?";
		Record rd1 = Db.findFirst(sqlOrg, orgId, R.Dict.STATUS_AVAILABLE);
		relationNum = rd1.getLong("num");

		if (relationNum > 0)
			return false;

		String sqlRole = "select count(1)  as num from sys_role where organization_id = ? and available = ?";
		Record rd2 = Db.findFirst(sqlRole, orgId, R.Dict.STATUS_AVAILABLE);
		relationNum = rd2.getLong("num");
		if (relationNum > 0)
			return false;

		String sqlUser = "select count(1)  as num from sys_user where (company_id = ? or department_id= ?)and available = ?";
		Record rd3 = Db.findFirst(sqlUser, orgId, orgId, R.Dict.STATUS_AVAILABLE);
		relationNum = rd3.getLong("num");
		if (relationNum > 0)
			return false;

		return allowDelete;
	}

	public List<Organization> findSubOrgListById(final Long orgId) {
		String sql = "select * from sys_organization where FIND_IN_SET(id, queryChildrenOrganization(?))  and  available =? order by priority asc";
		List<Organization> list = Organization.dao.findByCache(R.CacheName.GLOBAL_ORG_DATA, 1L, sql, orgId,
				R.Dict.STATUS_AVAILABLE); // 后台根据父节点查询出的数据列表
		return list;
	}

	/**
	 * 
	 * @Title:loadTreeOnceTime
	 * @Description: 一次性加载所有资源树，构建jstree插件树形结构对象列表
	 * @param onlyCompany
	 *            是否只加载公司类型机构（包含：总公司、分公司）
	 * @return List<Node> 返回类型
	 * @throws
	 * @anthor yixiaoping<thinker163@163.com>
	 * @date 2016年1月26日 上午10:06:46
	 */
	public List<Node> loadTreeOnceTime(boolean onlyCompany) {
		Long orgId = this.getCompanyId();// 加载用户所属公司组织机构树
		List<Organization> list = this.findSubOrgListById(orgId);

		HashMap<Long, Organization> orgMap = new HashMap<Long, Organization>();
		TreeMap<Long, List<Organization>> subOrgMap = new TreeMap<Long, List<Organization>>();
		for (Organization org : list) {
			Long id = org.getId();
			Long pid = org.getParentId();
			String orgType = org.getOrgType();

			if (onlyCompany) {
				if (R.Dict.ORG_COM.equals(orgType) || R.Dict.ORG_BR.equals(orgType)) {
					if (id != orgId) {
						List<Organization> subList = subOrgMap.get(pid);
						if (subList == null)
							subList = new ArrayList<Organization>();
						subList.add(org);
						subOrgMap.put(pid, subList);
					}
					orgMap.put(id, org);
				}
			} else {
				if (id != orgId) {
					List<Organization> subList = subOrgMap.get(pid);
					if (subList == null)
						subList = new ArrayList<Organization>();
					subList.add(org);
					subOrgMap.put(pid, subList);
				}
				orgMap.put(id, org);
			}
		}

		List<Node> nodeList = new ArrayList<Node>();
		Node rootNode = buildTreeNode(orgId, subOrgMap, orgMap);
		nodeList.add(rootNode);
		return nodeList;
	}

	/**
	 * 
	 * @Title:递归构建树jstree插件树形节点对象
	 * @Description:
	 * @param parentId
	 *            当前组织机构ID
	 * @param subResMap
	 *            {key: 组织机构IDLong,VALUE: 子节点列表List}
	 * @param resMap
	 *            {key: 组织机构IDLong,VALUE: 组织机构对象}
	 * @return
	 * @anthor yixiaoping<thinker163@163.com>
	 * @date 2016年1月23日 下午2:09:12
	 */
	private Node buildTreeNode(Long parentId, TreeMap<Long, List<Organization>> subOrgMap,
			HashMap<Long, Organization> orgMap) {
		List<Organization> subList = subOrgMap.get(parentId);
		Node node = new Node();

		Organization org = orgMap.get(parentId);
		node.setId(org.getId().toString());
		node.setText(org.getName());
		node.setType(org.getOrgType().toString());

		if (CollectionUtils.isNotEmpty(subList)) {
			List<Node> childrenNodes = new ArrayList<Node>();
			for (Organization subOrg : subList) {
				Long subOrgId = subOrg.getId();
				Node e = this.buildTreeNode(subOrgId, subOrgMap, orgMap);
				childrenNodes.add(e);
			}
			node.setChildren(childrenNodes);
		}
		return node;
	}

	/**
	 * 
	 * @Title:保存组织机构（新增、修改）
	 * @Description:
	 * @param organization
	 *            组织机构
	 * @return
	 * @anthor yixiaoping<thinker163@163.com>
	 * @date 2016年1月24日 下午9:59:35
	 */
	public Organization saveOrganization(Organization organization) {
		Long id = organization.getId();
		if (id == null) {
			Long pid = organization.getParentId();
			int priority = this.findMaxPrioritybyPid(pid) + 1;

			id = Sequence.getSequence();
			organization.setId(id);
			organization.setAvailable(Integer.valueOf(R.Dict.STATUS_AVAILABLE));
			organization.setPriority(priority);
			organization.setCreatetime(new Date());
			organization.setCreator(this.getLoginUser().getPramaryPrincipal());

			Organization parent = this.findOrganizationById(organization.getParentId());
			organization.setPath(parent.getPath() + "/" + organization.getName());
			organization.save();
		} else {
			Organization oldOrganization = Organization.dao.findById(id);
			oldOrganization.setName(organization.getName());
			;
			oldOrganization.setRemark(organization.getRemark());
			oldOrganization.update();
		}
		return organization;
	}

	/**
	 * 
	 * @Title:构建JSTREE树形插件节点对象
	 * @Description:
	 * @param resource
	 *            组织机构对象
	 * @return
	 * @anthor yixiaoping<thinker163@163.com>
	 * @date 2016年1月24日 下午9:59:54
	 */
	public Node buildJstreeNode(Organization organization) {
		Node node = new Node();

		node.setId(organization.getId().toString());
		node.setText(organization.getName());
		node.setType(organization.getOrgType());

		return node;
	}

	/**
	 * 
	 * @Title:根据ID查询子组织机构中优先级最大的值
	 * @Description:
	 * @param parentId
	 *            组织机构ID
	 * @return
	 * @anthor yixiaoping<thinker163@163.com>
	 * @date 2016年1月24日 下午9:59:03
	 */
	public int findMaxPrioritybyPid(Long parentId) {
		String sql = "select max(priority)  as priority from sys_organization where parent_id = ? and available =?";
		Organization data = Organization.dao.findFirst(sql, parentId, R.Dict.STATUS_AVAILABLE);
		return data.getPriority() == null ? 0 : data.getPriority();
	}
}
